#pragma once

#include <iostream>
#include <string>
#include <vector>
#include <unordered_map>
#include <sstream>
#include <functional>

const static std::string base_sep = "\r\n";
const static std::string line_sep = ": ";
const static std::string prefixpath = "wwwroot";
const static std::string spacesep = " ";
const static std::string homepage = "index.html";
const static std::string httpversion = "HTTP/1.1";
const static std::string suffixsep = ".";
const static std::string argcsep = "?";
const static std::string html_404 = "wwwroot/404.html";
class Request
{
private:
    std::string GetLine(std::string &reqstr)
    {
        auto pos = reqstr.find(base_sep);
        if (pos == std::string::npos)
        {
            return std::string();
        }
        std::string line = reqstr.substr(0, pos);
        reqstr.erase(0, pos+ base_sep.size()); // 因为有erase，不能加const
        //我艹 这个记得把分隔符sep也要删掉
        return line.empty() ? base_sep : line;
    }
    void ParseReqLine()
    {
        // 对请求行反序列化
        // 请求行格式
        // 请求方法 + 空格 + URI + 空格 + HTTP版本 + '/r/n'
        std::stringstream ss(_req_line);
        ss >> _method >> _url >> _version;

        // 处理GET方法
        if (strcmp(_method.c_str(), "GET") == 0)
        {
            auto pos = _url.find(argcsep);
            if (!(pos == std::string::npos))
            {
                // 把参数加到正文
                _body_text = _url.substr(pos + argcsep.size());
                // 删除参数部分 只留下路径
                _url.resize(pos);
            }
        }
        _path += _url;

        if (_path[_path.size() - 1] == '/')
        {
            _path += homepage;
        }

        // 找资源后缀
        // 先找.     得从最后倒着找
        auto pos = _path.rfind(suffixsep);
        if (pos != std::string::npos)
        {
            _suffix = _path.substr(pos);
        }
        else
        {
            _suffix = ".default";
        }
    }
    void ParseReqHeader()
    {
        // 对请求报头反序列化
        for (auto &kv : _req_headers)
        {
            // 报头格式
            // Key: Value
            auto pos = kv.find(line_sep);
            if (pos == std::string::npos)
                continue;
            std::string key = kv.substr(0, pos);
            std::string value = kv.substr(pos + line_sep.size());
            if (key.empty() || value.empty())
                continue;
            _headers_kv.insert(std::make_pair(key, value));
        }
    }

public:
    Request()
        // 防止反序列化时未添加空行
        : _blank_line(base_sep),
          _path(prefixpath)
    {
    }

    void Deserialize(std::string &reqstr)
    {
       // std::cout << reqstr << std::endl;
        // 基本反序列化
        // 分离请求行
        _req_line = GetLine(reqstr);

        //分离请求报头
        std::string line;
        do{
            line = GetLine(reqstr);
            if(line.empty())
                break;
            if (line == base_sep)
                break;
            _req_headers.push_back(line);
        } while (true);

        // 得到每一行后reqstr会变化
        //分离报文
        if (!reqstr.empty())
        {
            _body_text = reqstr;
        }

        // 进一步反序列化
        //对请求行反序列化
        ParseReqLine();
        //对请求报头反序列化
        ParseReqHeader();
    }
    void Print()
    {
        // std::cout << "----------------------------" << std::endl;
        // std::cout << "###" << _req_line << std::endl;
        // std::cout << "Method: " << _method << std::endl;
        // std::cout << "Url: " << _url << std::endl;
        // std::cout << "Version: " << _version << std::endl;
        // for (auto &header : _req_headers)
        // {
        //     std::cout << "@@@" << header << std::endl;
        // }
        // std::cout << "***" << _blank_line;
        // std::cout << ">>>" << _body_text << std::endl;

    }
    std::string URL()
    {
        return _url;
    }
    std::string Path()
    {
        return _path;
    }
    std::string Suffix()
    {
        return _suffix;
    }
    std::string Method()
    {
        return _method;
    }
    std::string GetRequestBody()
    {
        return _body_text;
    }

private:
    // 基本的httprequest格式
    std::string _req_line;
    std::vector<std::string> _req_headers;
    std::string _blank_line;
    std::string _body_text;

    // 更具体的属性，需要进一步反序列化
    // http方法   资源路径   版本
    std::string _method;
    std::string _url;
    std::string _path;
    std::string _suffix; // 资源后缀(文件类型)
    std::string _version;
    // 报头属性
    std::unordered_map<std::string, std::string> _headers_kv;
};

class Response
{
public:
    Response()
        : _version(httpversion), _blank_line(base_sep)
    {
    }
    void AddCode(const int code, const std::string &desc)
    {
        _status_code = code;
        _desc = desc;
    }
    void AddHeader(const std::string &k, const std::string &v)
    {
        // _headers_kv.insert(std::make_pair(k, v));
        _headers_kv[k] = v;
    }
    void AddBodyText(const std::string &body)
    {
        _resp_body_text = body;
    }
    std::string Serialize()
    {
        // 1.构建状态行
        _status_line = _version + spacesep + std::to_string(_status_code) + spacesep + _desc + base_sep;
        // 2.构建应答报头
        for (auto &kv : _headers_kv)
        {
            std::string headerline = kv.first + line_sep + kv.second + base_sep;
            _resp_headers.push_back(headerline);
        }
        // 3.空行和正文

        // 4.正式序列化
        std::string responsestr = _status_line;
        for (auto &headers : _resp_headers)
        {
            responsestr += headers;
        }
        responsestr += _blank_line;
        responsestr += _resp_body_text;
        return responsestr;
    }

private:
    // 基本的httpresponse格式
    std::string _status_line;
    std::vector<std::string> _resp_headers;
    std::string _blank_line;
    std::string _resp_body_text;

    // httpresponse base属性
    // http版本   状态码    状态码描述
    std::string _version;
    int _status_code;
    std::string _desc;
    // 报头属性
    std::unordered_map<std::string, std::string> _headers_kv;
};

using func_t = std::function<Response(Request)>;

class HttpService
{
private:
    // 获取资源
    std::string GetFileContent(const std::string &path)
    {
        std::ifstream in(path, std::ios::binary);
        if (!in.is_open())
            return std::string();
        // 定位到最后求大小
        in.seekg(0, in.end);
        int filesize = in.tellg();
        in.seekg(0, in.beg);

        std::string content;
        content.resize(filesize);
        in.read((char *)content.c_str(), filesize);
        in.close();
        return content;
    }

public:
    HttpService()
    {
        _code_to_desc.insert(std::make_pair(100, "Continue"));
        _code_to_desc.insert(std::make_pair(200, "OK"));
        _code_to_desc.insert(std::make_pair(201, "Created"));
        _code_to_desc.insert(std::make_pair(301, "Moved Permanently"));
        _code_to_desc.insert(std::make_pair(302, "Found"));
        _code_to_desc.insert(std::make_pair(404, "Not Found"));

        _mime_type.insert(std::make_pair(".html", "text/html"));
        _mime_type.insert(std::make_pair(".jpg", "image/jpeg"));
        _mime_type.insert(std::make_pair(".png", "image/png"));
        _mime_type.insert(std::make_pair(".default", "text/html"));
    }
    std::string HandleHttpRequest(std::string &reqstr)
    {
#define TEST
#ifndef TEST
        std::string message = "HTTP/1.1 200 OK\r\n";
        message += "Content-Type: text/html\r\n";
        message += "\r\n";
        message += "<html><h1>hello http!\n</h1></html>";
        return message;
#else
        std::cout << "----------------------------------" << std::endl;
        std::cout << reqstr << std::endl;
        std::cout << "----------------------------------" << std::endl;
        Request req;
        req.Deserialize(reqstr);
        req.Print();

        Response resp;
        // 处理重定向
        if (req.Path() == "wwwroot/redir")
        {
            std::string redir_path = "https://www.qq.com";
            resp.AddCode(301, _code_to_desc[301]);
            resp.AddHeader("Location", redir_path);
        }
        // 请求正文不为空
        else if (!req.GetRequestBody().empty())
        {
            if (IsServiceExit(req.Path()))
            {
                resp = _service_list[req.Path()](req);
            }
            // 如果不存在呢？
        }
        // 最基本的上层处理,处理静态资源
        else
        {
            // 打开资源二进制
            std::string content = GetFileContent(req.Path());
            // 内容为空，显示404页面
            if (content.empty())
            {
                std::string content_404html = GetFileContent("wwwroot/404.html");
                resp.AddCode(404, _code_to_desc[404]);
                resp.AddHeader("Content-Length", std::to_string(content_404html.size()));
                resp.AddHeader("Content-Type", _mime_type[req.Suffix()]);
                resp.AddBodyText(content_404html);
            }
            // 作为正文部分
            else
            {
                resp.AddCode(200, _code_to_desc[200]);
                resp.AddHeader("Content-Length", std::to_string(content.size()));
                resp.AddHeader("Content-Type", _mime_type[req.Suffix()]);
                resp.AddBodyText(content);
            }
        }
        std::string respstr = resp.Serialize();
        return respstr;
#endif
    }
    void InsertService(const std::string &ServiceName, func_t service)
    {
        std::string s = ServiceName;
        _service_list[s] = service;
    }
    bool IsServiceExit(const std::string &ServiceName)
    {
        auto iter = _service_list.find(ServiceName);
        if (iter == _service_list.end())
            return false;
        return true;
    }

private:
    // 响应正文格式
    std::unordered_map<std::string, std::string> _mime_type;
    std::unordered_map<int, std::string> _code_to_desc;
    std::unordered_map<std::string, func_t> _service_list;
};
